package com.gf.framework.web.translate;

import com.gf.framework.common.utils.ReflectUtil;
import com.gf.framework.common.utils.SpringContextUtil;
import com.gf.framework.web.annotation.Translate;
import com.gf.framework.web.annotation.TranslateField;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author gaofei
 * @date 2022/8/27 13:52
 * 默认类型的转换器
 */
@Slf4j
public class ObjectTypeConvert implements TranslateTypeConvert<Object> {
    /**
     * 翻译对象缓存
     */
    private final Map<String, Translatable<Object, Object>> translatableMap = new ConcurrentHashMap<>();
    /**
     * class 和 需要翻译的字段的缓存
     */
    private final Map<String, List<Field>> classFieldMap = new ConcurrentHashMap<>();

    /**
     * class 和 需要翻译的内部字段的缓存
     */
    private final Map<String, List<Field>> classTranslateFieldMap = new ConcurrentHashMap<>();

    private final static String THIS_STR = "this";

    /**
     * 对象翻译
     * @param object 需要字段翻译的对象
     */
    @Override
    public void convert(Object object) {
        if (Objects.isNull(object)) {
            return;
        }
        // 翻译当前对象字段
        getFieldList(object.getClass()).forEach(field -> translateField(object, field));

        // 翻译内部字段
        getTranslateFieldList(object.getClass()).forEach(field -> {
            try {
                Object subObject = ReflectUtil.invokeGet(object, field);
                if (subObject instanceof Collection) {
                    convertCollection(new ArrayList<>((Collection<?>) subObject));
                } else {
                    convert(subObject);
                }
            } catch (Exception e) {
                log.error("翻译错误", e);
            }
        });
    }

    /**
     * 对象翻译
     * @param list 对象列表
     */
    @Override
    public void convertCollection(List<Object> list) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        Class<?> classes = list.get(0).getClass();

        getFieldList(classes).forEach(field -> collectionTranslateField(list, field));
        getTranslateFieldList(classes).forEach(field -> list.forEach(o -> {
            Object subObject = ReflectUtil.invokeGet(o, field);
            if (Objects.isNull(subObject)) {
                return;
            }
            if (subObject instanceof Collection<?>) {
                convertCollection(new ArrayList<>((Collection<?>) subObject));
            } else {
                convert(subObject);
            }
        }));
    }

    /**
     * 放最后执行
     * @return 执行顺序
     */
    @Override
    public int order() {
        return Integer.MAX_VALUE;
    }

    /**
     * 自身需要翻译的
     * @param classes 类型
     * @return 自身需要翻译的字段列表
     */
    private List<Field> getFieldList(Class<?> classes) {
        return classFieldMap.computeIfAbsent(classes.getName(),
                aClass -> Arrays.stream(ReflectUtil.getFields(classes))
                        .filter(field -> field.getAnnotation(Translate.class) != null).collect(Collectors.toList()));
    }

    /**
     * 有内部字段需要翻译的
     * @param classes 类型
     * @return 有内部字段需要翻译的字段列表
     */
    private List<Field> getTranslateFieldList(Class<?> classes) {
        return classTranslateFieldMap.computeIfAbsent(classes.getName(),
                aClass -> Arrays.stream(ReflectUtil.getFields(classes))
                        .filter(field -> field.getAnnotation(TranslateField.class) != null).
                        collect(Collectors.toList()));
    }

    /**
     * 翻译一个字段
     * @param vo 对象
     * @param field 内部需要翻译的字段
     */
    @SuppressWarnings("unchecked")
    private void translateField(Object vo, Field field) {
        try {
            Translate annotation = field.getAnnotation(Translate.class);
            Object fieldValue;
            if (THIS_STR.equalsIgnoreCase(annotation.from())) {
                fieldValue = vo;
            }
            else {
                fieldValue = ReflectUtil.invokeGet(vo, annotation.from());
            }
            if (annotation.notnull() && Objects.isNull(fieldValue)) {
                return;
            }

            Translatable<Object, Object> translatable = translatableMap.computeIfAbsent(
                    annotation.translator().getName(), v -> SpringContextUtil.getBean(annotation.translator()));

            Object translate = translatable.translate(fieldValue, annotation.dataSource(), annotation.param());
            if (translate == null) {
                return;
            }
            ReflectUtil.invokeSet(vo, field, translate);
        } catch (Exception e) {
            log.error("翻译错误", e);
        }
    }

    @SuppressWarnings("all")
    private void collectionTranslateField(List<Object> objects, Field field) {
        try {
            Translate annotation = field.getAnnotation(Translate.class);
            List<Object> fieldValues;
            if (THIS_STR.equalsIgnoreCase(annotation.from())) {
                fieldValues = objects;
            }
            else if (annotation.notnull()) {
                // 需要过滤空字段
                List<Object> tempObjs = new ArrayList<>(objects.size());
                fieldValues = new ArrayList<>(objects.size());
                for (Object o : objects) {
                    Object fieldValue = ReflectUtil.invokeGet(o, annotation.from());
                    if (Objects.isNull(fieldValue)) {
                        continue;
                    }

                    tempObjs.add(o);
                    fieldValues.add(fieldValue);
                }
                objects = tempObjs;
            }
            else {
                // 不需要过滤空字段
                fieldValues = objects.stream()
                        .map(o -> ReflectUtil.invokeGet(o, annotation.from())).collect(Collectors.toList());
            }

            Translatable<Object, Object> translatable = translatableMap.computeIfAbsent(
                    annotation.translator().getName(), v -> SpringContextUtil.getBean(annotation.translator()));

            List<Object> translates = translatable.translateList(fieldValues, annotation.dataSource(), annotation.param());

            for (int i = 0; i < translates.size(); i++) {
                ReflectUtil.invokeSet(objects.get(i), field, translates.get(i));
            }
        } catch (Exception e) {
            log.error("翻译错误", e);
        }
    }
}
